#include <iostream>
#include <string>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

typedef websocketpp::server<websocketpp::config::asio> wsserver_t;

void print(const std::string& str)
{
    std::cout << str << std::endl;
}
//http_callback被服务器回调时，只要我们构建了resp，同时设置好响应状态码、响应正文、响应头部字段后，则会给浏览器自动返回一个http响应报文
void http_callback(wsserver_t *svr, websocketpp::connection_hdl hdl) 
{
    wsserver_t::connection_ptr conn = svr->get_con_from_hdl(hdl);
    std::cout << "body: " << conn->get_request_body() << std::endl;
    websocketpp::http::parser::request req = conn->get_request();
    std::cout << "method: " << req.get_method() << std::endl;
    std::cout << "uri: " << req.get_uri() << std::endl;

    std::string resp = "<html> <body> <h1> hello world </h1></body></html>";
    conn->set_body(resp);
    conn->append_header("Content-Type", "text/html");
    conn->set_status(websocketpp::http::status_code::value::ok);
    //---bind影响的是实际调用时的传参，并不影响类型！set_timer参数的function类型是什么，set_timer里面该怎么调就怎么传参，只不过这个传参
    //   实际传了也没用，因为bind可能绑死参数了，所以不管你里面怎么正确传递参数的调用都是没用的！---
    wsserver_t::timer_ptr tp = svr->set_timer(10000, std::bind(&print, "rygttm"));
    //获取set_timer返回的定时器对象
    tp->cancel();//取消定时器，会导致定时任务立即被执行
}
void wsopen_callback(wsserver_t *svr, websocketpp::connection_hdl hdl) 
{
    std::cout << "WebSocket握手成功!!\n";
}
void wsclose_callback(wsserver_t *svr, websocketpp::connection_hdl hdl) 
{
    std::cout << "WebSocket连接断开!!\n";
}
void wsmessage_callback(wsserver_t *svr, websocketpp::connection_hdl hdl, wsserver_t::message_ptr msgptr) 
{
    std::cout << "wsmsg: " << msgptr->get_payload() << std::endl;//将客户端发送的消息回显到服务器上
    std::string resp = "Client say: " + msgptr->get_payload();
    wsserver_t::connection_ptr conn = svr->get_con_from_hdl(hdl);
    conn->send(resp, websocketpp::frame::opcode::text);
}

int main()
{
    //1.实例化server对象
    wsserver_t wssvr;
    //2.设置日志等级为none
    wssvr.set_access_channels(websocketpp::log::alevel::none);
    //3.初始化asio异步IO调度器
    wssvr.init_asio();
    wssvr.set_reuse_addr(true);
    //4.设置WebSocket服务器的事件处理回调函数
    // websocketpp中的标准函数声明: 
    // -> void set_http_handler(http_handler h);  typedef lib::function<void(connection_hdl)> http_handler;
    //我们自己定义的http_callback回调函数比标准的函数格式多了一个参数*svr，只要在bind的时候绑定传参即可传递给function对象http_handler
    wssvr.set_http_handler(std::bind(&http_callback, &wssvr, std::placeholders::_1));
    wssvr.set_open_handler(std::bind(&wsopen_callback, &wssvr, std::placeholders::_1));
    wssvr.set_close_handler(std::bind(&wsclose_callback, &wssvr, std::placeholders::_1));
    wssvr.set_message_handler(std::bind(&wsmessage_callback, &wssvr, std::placeholders::_1, std::placeholders::_2));
    //---bind一般有两种用法，一种绑死，一种预留参数位置，等待函数内部传参---
    //5.设置服务器绑定的监听端口号，监听端口号上是否有连接到来
    wssvr.listen(8080);
    //6.accept获取内核监听队列中已经完成三次握手的连接，开始通信
    wssvr.start_accept();
    //7.启动运行WebSocket服务器
    wssvr.run();
    return 0;
}